//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;

use email::MimeMessage;
use toml::Value;

use error::EmailErrorKind as EK;
use error::MapErrInto;
use result::Result;

use libimagref::reference::Ref;
use libimagref::flags::RefFlags;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagstore::toml_ext::*;
use libimagerror::into::IntoError;

/// A Email is a Reference object to a file on the filesystem
///
/// We therefor use the `libimagref` implementation to create a reference to the filesystem file,
/// plus we add custom headers for value caching.
///
#[derive(Debug)]
pub struct Email<'a> {
    entry: Ref<'a>,
}

impl<'a> Email<'a> {

    pub fn is_email(fle: &FileLockEntry) -> Result<bool> {
        unimplemented!()
    }

    pub fn get(store: &'a Store, si: StoreId) -> Result<Email<'a>> {
        unimplemented!()
    }

    /// Try to build an Email object based on an existing FileLockEntry object
    pub fn from_filelockentry(fle: FileLockEntry<'a>) -> Result<Email<'a>> {
        unimplemented!()
    }

    /// Try to parse an Email from a String, create an Email object in the Store
    ///
    /// # Parameters
    ///
    /// * `s` The message content
    /// * `pb` The path where the message lives
    /// * `store` The libimagstore::store::Store to put this message into
    ///
    pub fn from_str(s: &str, pb: PathBuf, store: &'a Store) -> Result<Email<'a>> {
        let msg = try!(MimeMessage::parse(s).map_err_into(EK::EmailParseError));

        let flags = RefFlags::default().with_content_hashing(true).with_permission_tracking(false);

        let from = try!(msg.headers
            .get(String::from("From"))
            .map(|s| Value::String(s.name.clone()))
            .ok_or(EK::EmailHeaderErrorMissingFieldFrom.into_error()));

        let msgid = try!(msg.headers
            .get(String::from("Message-Id"))
            .map(|s| Value::String(s.name.clone()))
            .ok_or(EK::EmailHeaderErrorMissingFieldMsgId.into_error()));

        let to = try!(msg.headers
            .get(String::from("To"))
            .map(|s| Value::String(s.name.clone()))
            .ok_or(EK::EmailHeaderErrorMissingFieldTo.into_error()));

        let date = try!(msg.headers
            .get(String::from("Date"))
            .map(|s| Value::String(s.name.clone()))
            .ok_or(EK::EmailHeaderErrorMissingFieldDate.into_error()));

        let inreplyto = try!(msg.headers
            .get(String::from("In-Reply-To"))
            .map(|s| Value::String(s.name.clone()))
            .ok_or(EK::EmailHeaderErrorMissingFieldInReplyTo.into_error()));

        let mut rf = try!(Ref::create(store, pb, flags).map_err_into(EK::CannotCreateRef));

        {
            let mut hdr = rf.get_header_mut();

            try!(hdr.insert("email.header.from", from)
                 .map_err_into(EK::FileLockEntryHeaderWriteError));

            try!(hdr.insert("email.header.msgid", msgid)
                 .map_err_into(EK::FileLockEntryHeaderWriteError));

            try!(hdr.insert("email.header.to", to)
                 .map_err_into(EK::FileLockEntryHeaderWriteError));

            try!(hdr.insert("email.header.date", date)
                 .map_err_into(EK::FileLockEntryHeaderWriteError));

            try!(hdr.insert("email.header.in-reply-to", inreplyto)
                 .map_err_into(EK::FileLockEntryHeaderWriteError));
        }

        Ok(Email { entry: rf })
    }

    ///
    /// Instance functions
    ///

    pub fn sender(&self) -> Result<String> {
        unimplemented!()
    }

    pub fn msgid(&self) -> Result<String> {
        unimplemented!()
    }

    pub fn date(&self) -> Result<String> {
        unimplemented!()
    }

}

impl<'a> Into<Ref<'a>> for Email<'a> {

    fn into(self) -> Ref<'a> {
        self.entry
    }

}

